package org.grapes.wine.api.server.exception;

import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.grapes.wine.api.bean.MethodErrorBean;
import org.grapes.wine.api.bean.ObjectFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

public class MethodException extends Exception {

	private static final long serialVersionUID = 1L;

	private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
			.newInstance();
	private Document doc = null;
	private int errorCode;
	private String message;

	public Document getDocument() {
		return doc;
	}

	public int getErrorCode() {
		return errorCode;
	}

	public String getMessage() {
		return message;
	}

	/**
	 * generate Error Document
	 * 
	 * @param errorCode
	 */
	public MethodException(int errorCode) {
		this.errorCode = errorCode;
		switch (errorCode) {
		case MethodErrorCode.METHOD_NOT_FOUND:
			message = "Method not found";
			doc = renderErrorDocumentByJAXB(MethodErrorCode.METHOD_NOT_FOUND,
					message);
			break;
		case MethodErrorCode.PARAMETER_NOT_MATCH:
			message = "Parameter not match";
			doc = renderErrorDocumentByJAXB(
					MethodErrorCode.PARAMETER_NOT_MATCH, message);
			break;
		case MethodErrorCode.DOCUMENT_NULL:
			message = "Document is null, to know more please inquire administration";
			doc = renderErrorDocumentByJAXB(MethodErrorCode.DOCUMENT_NULL,
					message);
			break;
		case MethodErrorCode.SQL_RESTRICTION:
			message = "Only insert/select/delete/update SQL statement is supported";
			doc = renderErrorDocumentByJAXB(MethodErrorCode.SQL_RESTRICTION,
					message);
			break;
		case MethodErrorCode.SQL_STATEMENT_EMPTY:
			message = "SQL statement must not empty";
			doc = renderErrorDocumentByJAXB(
					MethodErrorCode.SQL_STATEMENT_EMPTY, message);
			break;
		case MethodErrorCode.HIBERNATE_STATE_ERROR:
			message = "HibernateHelper state error";
			doc = renderErrorDocumentByJAXB(
					MethodErrorCode.HIBERNATE_STATE_ERROR, message);
		default:
			message = "Unkown error, to know more please inquire administration";
			doc = renderErrorDocumentByJAXB(MethodErrorCode.UNKNOWN_ERROR,
					message);
		}
	}

	public MethodException(SQLException e) {
		errorCode = e.getErrorCode();
		message = e.getMessage();
		// doc = renderErrorDocument(errorCode, message);
		doc = renderErrorDocumentByJAXB(errorCode, message);
	}

	public MethodException() {
	}

	private Document renderErrorDocumentByJAXB(int errorCode, String msg) {
		Document errorDoc = BuildNewDocument();
		try {
			ObjectFactory factory = new ObjectFactory();
			MethodErrorBean errorBean = factory.createMethodErrorBean();
			errorBean.setErrorCode(errorCode);
			errorBean.setDescription(msg);
			JAXBContext context = JAXBContext
					.newInstance(MethodErrorBean.class);
			Marshaller marshaller = context.createMarshaller();
			marshaller.marshal(errorBean, errorDoc);
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return errorDoc;
	}

	private Document BuildNewDocument() {
		DocumentBuilderFactory documentBuilderFactory;
		documentBuilderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = null;
		try {
			docBuilder = documentBuilderFactory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			try {
				throw new ServletException(
						"unable to create DocumentBuilderFactory", e);
			} catch (ServletException e1) {
				e1.printStackTrace();
			}
		}
		return docBuilder.newDocument();
	}

	@Deprecated
	private Document renderErrorDocument(int errCode, String msg) {
		DocumentBuilder docBuilder = null;
		try {
			docBuilder = documentBuilderFactory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}

		// create the DOM document
		Document doc = docBuilder.newDocument();
		Element wineResponse = doc.createElement("wineResposne");
		doc.appendChild(wineResponse);
		Element error = doc.createElement("error");
		wineResponse.appendChild(error);
		Element errorCode = doc.createElement("errorCode");
		Text errorText = doc.createTextNode(Integer.toString(errCode));
		errorCode.appendChild(errorText);
		error.appendChild(errorCode);
		Element description = doc.createElement("description");
		Text descText = doc.createTextNode(msg);
		description.appendChild(descText);
		error.appendChild(description);

		return doc;
	}
}
